﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using System.Collections;
using System.IO;
using System.Reflection;

namespace SharePointUsers
{
    public partial class MainForm : Form
    {
        #region Private Members
        //Prepare SPU object
        SPUmanager spuManagerObj = new SPUmanager();
        int SiteCount = 0;
        int SelectedSiteCount = 0;
        int AppCount = 0;
        bool ApplicationsLoaded = false;
        private bool UpdatingNode = false;
        private CreateReportWizard ReportDesigner = new CreateReportWizard();
        #endregion
        public bool PickingProperties { get; set; }
        public bool PickingScopes { get; set; }
        public MainForm()
        {
            InitializeComponent();
            
        }
        private DataTable GetFarmStatistics(SPWebService CurrentFarm)
        {
            DataTable Summary = new DataTable("Farm Statistics");

            Summary.Columns.Add("Applications");
            Summary.Columns.Add("Sites");
            int Application = 0;
            int SiteCollections = 0;
            foreach (SPWebApplication wa in CurrentFarm.WebApplications)
            {
                Application++;
                foreach (SPContentDatabase contentdb in wa.ContentDatabases)
                {
                    SiteCollections += contentdb.CurrentSiteCount;
                }
            }
            Summary.Rows.Add(Application, SiteCollections);

            return Summary;

        }
        private DataTable GetSPDatabases()
        {
            DataTable Databases = new DataTable("Databases");
            Databases.Columns.Add("ID");
            Databases.Columns.Add("Web Application");
            Databases.Columns.Add("DB Name");
            Databases.Columns.Add("Type");
            Databases.Columns.Add("Total Sites Count");
            Databases.Columns.Add("Site Collection");
            Databases.Columns.Add("Status");
            Databases.Columns.Add("Size");

            //Check if the farm node is loaded or not
            if (treeViewSites.Nodes.Count == 0) return Databases;
            SPWebService CurrentFarm = SPWebService.ContentService;
            int ID = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                // The content dbs are not loaded yet
                if(App.Nodes.Count <= 0)
                {
                    //Load the content dbs
                    SPWebApplication Wa = CurrentFarm.WebApplications[App.Text];
                    TreeNode ContentDbsCollectionNode = CreateContentDbsCollection(App, Wa.ContentDatabases.Count);

                    LoadContentDb(Wa, ContentDbsCollectionNode);
                }
                //Iterate through content databases
                foreach (TreeNode contentDb in App.Nodes)
                {
                    foreach (TreeNode sc in contentDb.Nodes)
                    {
                        try
                        {
                            DataRow Dbrecord = Databases.NewRow();
                            Dbrecord["ID"] = ID++;
                            Dbrecord["Web Application"] = GetSPObjectProperty(App,"Name");
                            Dbrecord["DB Name"] = GetSPObjectProperty(contentDb, "Name");
                            Dbrecord["Type"] = "Content Database";
                            double Size = double.Parse(GetSPObjectProperty(contentDb, "DiskSizeRequired"));
                            Size = Size / (Convert.ToDouble(1024) * Convert.ToDouble(1024) * Convert.ToDouble(1024));
                            Dbrecord["Size"] = Math.Round(Size, 3);
                            Dbrecord["Total Sites Count"] = GetSPObjectProperty(contentDb, "CurrentSiteCount");
                            Dbrecord["Site Collection"] = GetSPObjectProperty(sc, "Url");
                            Dbrecord["Status"] = GetSPObjectProperty(contentDb, "Status");
                            Databases.Rows.Add(Dbrecord);
                        }
                        catch
                        {
                        }
                        
                    }

                }
            }
            return Databases;
        }
        private TreeNode LoadApplication(TreeNode ApplicationsNode, SPWebApplication Wa,bool LoadContentDbs)
        {
            TreeNode App = new TreeNode(Wa.Name);
            //Web application icon
            App.ImageIndex = 39;
            App.Checked = true;
            SPObject AppObj = SPdalHelper.PopulateApplication(Wa, LoadContentDbs, false);
            App.Tag = AppObj;
            App.Name = AppObj.Properties[Reporter.GetIdentifierPropertyName(AppObj.WSSType)];
            ApplicationsNode.Nodes.Add(App);
            AppCount++;

            //Load Web App features
            LoadFeatures(Wa, App, SPFeatureScope.WebApplication);

            //Load Content dbs
            if (LoadContentDbs)
            {
                TreeNode ContentDbsCollectionNode = CreateContentDbsCollection(App, Wa.ContentDatabases.Count);
                LoadContentDb(Wa, ContentDbsCollectionNode);
            }

            return App;
        }
        private TreeNode CreateApplicationCollection(TreeNode FarmNode, SPWebService WebService, bool Loaded)
        {
            TreeNode AppCollection = new TreeNode("Web Applications");
            //Web application icon
            AppCollection.ImageIndex = 39;
            AppCollection.Checked = false;
            AppCollection.Tag = SPdalHelper.PopulateCollection(SPType.WebApplication, WebService.WebApplications.Count, Loaded,false);
            FarmNode.Nodes.Add(AppCollection);
            return AppCollection;
        }
        private void LoadAllApps(TreeNode FarmNode,bool LoadContentDbs)
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            TreeNode AppCollection = CreateApplicationCollection(FarmNode, CurrentFarm, true);
          
            foreach (SPWebApplication wa in CurrentFarm.WebApplications)
            {
                LoadApplication(AppCollection, wa, LoadContentDbs);
            }
        }
        private void LoadFarmAndAppsOnly()
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;
            treeViewSites.Nodes.Clear();

            //Create the farm root node
            TreeNode FarmNode = new TreeNode(FarmObj.Name);
            FarmNode.ImageIndex = 42;
            FarmNode.Checked = true;
            SPObject FarmSPObj = SPdalHelper.PopulateFarm(FarmObj, false);
            FarmNode.Tag = FarmSPObj;
            FarmNode.Name = FarmSPObj.Properties[Reporter.GetIdentifierPropertyName(FarmSPObj.WSSType)];
            treeViewSites.Nodes.Add(FarmNode);

            //Load features
            LoadFarmFeatures(FarmObj, FarmNode);
            
            //Load All Apps
            LoadAllApps(FarmNode,false);

            ApplicationsLoaded = true;
            UpdatingNode = false;
            UpdateSiteCount();
        }
        private void LoadFarm()
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;
            treeViewSites.Nodes.Clear();

            //Create the farm root node
            TreeNode FarmNode = new TreeNode(FarmObj.Name);
            FarmNode.ImageIndex = 42;
            FarmNode.Checked = true;
            SPObject FarmSPObj = SPdalHelper.PopulateFarm(FarmObj, false); ;
            FarmNode.Tag = FarmSPObj;
            FarmNode.Name = FarmSPObj.Properties[Reporter.GetIdentifierPropertyName(FarmSPObj.WSSType)];
            treeViewSites.Nodes.Add(FarmNode);

            //Load features
            LoadFarmFeatures(FarmObj, FarmNode);


            //Load all apps and content dbs
            LoadAllApps(FarmNode,true);

            ApplicationsLoaded = true;
            UpdatingNode = false;
            UpdateSiteCount();
        }
        private TreeNode CreateContentDbsCollection(TreeNode AppNode, int Count)
        {
            TreeNode DBNode = new TreeNode("Content DBs");
            DBNode.Checked = false;
            DBNode.ImageIndex = 44;
            SPObject DB = SPdalHelper.PopulateCollection(SPType.ContentDatabase, Count, true, false);
            DBNode.Tag = DB;
            AppNode.Nodes.Add(DBNode);
            return DBNode;
        }
        private void LoadContentDbs()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The local farm is not loaded yet. Please load the farm SharePoint applications first.");
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;
            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));

            UpdatingNode = true;
            int ID = 1;
            foreach (TreeNode AppNode in treeViewSites.Nodes[0].Nodes)
            {
                //Skip unchecked nodes
                if (!AppNode.Checked)
                    continue;
                SPWebApplication Wa = CurrentFarm.WebApplications[AppNode.Text];
                TreeNode ContentDbsCollectionNode = CreateContentDbsCollection(AppNode,Wa.ContentDatabases.Count);
                LoadContentDb(Wa, ContentDbsCollectionNode);
            }
            UpdatingNode = false;

            
        
        }
        private void LoadContentDb(SPWebApplication WebApp, TreeNode AppNode)
        {
            UpdatingNode = true;
            TreeNode DBNode = null;
            foreach (SPContentDatabase db in WebApp.ContentDatabases)
            {
                DBNode = new TreeNode(db.Name);
                DBNode.Checked = false;
                DBNode.ImageIndex = 44;
                SPObject DB = SPdalHelper.PopulateContentDB(db, false);
                double Size = db.DiskSizeRequired;
                Size = Size / (Convert.ToDouble(1024) * Convert.ToDouble(1024) * Convert.ToDouble(1024));
                DB.Properties.Add("C: Size", Math.Round(Size, 3).ToString());
                DBNode.Tag = DB;
                DBNode.Name = DB.Properties[Reporter.GetIdentifierPropertyName(DB.WSSType)];
                AppNode.Nodes.Add(DBNode);
                LoadSiteCollections(WebApp, DBNode, false, 0);
            }

        }

        private void buttonLoadSites_Click(object sender, EventArgs e)
        {
            string ErrorMessage = "Error connecting to the local SharePoint farm. The farm is not available or you don't have enough access to load the sites";
            try
            {
                LoadFarm();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(ErrorMessage + string.Format("Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            "Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            UpdateSiteCount();
        }
        private void UpdateSiteCount()
        {
            labelSelectedSites.Text = string.Format("( {0} \\ {1} )", SelectedSiteCount, SiteCount);
            GUIcontroler();
        }
        private void GUIcontroler()
        {
            if (AppCount > 0 && SiteCount <= 0)
                loadSiteCollectionsToolStripMenuItem.Enabled = true;
            if(AppCount <= 0 || SiteCount > 0) 
                loadSiteCollectionsToolStripMenuItem.Enabled = false;
            
        }
        private string GetSPObjectProperty(TreeNode Node, string PropertyName)
        {
            string Value = "";
            if (Node != null && Node.Tag is SPObject)
            {
                SPObject spObj = Node.Tag as SPObject;
                if (spObj != null)
                {
                    if (spObj.Properties != null && 
                        spObj.Properties.ContainsKey(PropertyName) &&
                        spObj.Properties[PropertyName] != null)
                    {
                        Value = spObj.Properties[PropertyName];
                    }
                }
            }
            return Value;
        }
        private void GenerateUserReport(bool EntryForSiteCollections, bool EntryForSubSites)
        {
            //Check if the farm node is loaded or not
            if (treeViewSites.Nodes.Count == 0) return;

            //Generate a user report
            #region Generate the user report
            listBoxUsersList.Items.Clear();
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App,false,0);
                }
                foreach (TreeNode SiteCollection in App.Nodes)
                {
                    if (!SiteCollection.Checked)
                        continue;
                    string SiteCollectionUrl = GetSPObjectProperty(SiteCollection,"Url");
                    if (string.IsNullOrEmpty(SiteCollectionUrl)) continue;
                    using (SPSite site = new SPSite(SiteCollectionUrl))
                    {
                        spuManagerObj.GetSiteUsers(site.RootWeb, false, false);
                        if (EntryForSubSites)
                        {
                            bool Retry = true;
                            while (Retry)
                            {
                                Retry = false;
                                string WebTitle = "";
                                string WebUrl = "";
                                try
                                {

                                    using (SPWeb web = site.OpenWeb())
                                    {
                                        WebTitle = web.Title;
                                        WebUrl = web.Url;
                                        spuManagerObj.GetWebUsers(web, null);
                                    }
                                }
                                catch (Exception Ex)
                                {
                                    DialogResult Result = MessageBox.Show(string.Format("Error loading sites under site collection '{0}' Url='{1}'."
                                    + "\n\nMake sure you have access to the site or exclude it from the process in future runs to" +
                                    " avoid interruption.\n\nError details:\n {2}\n\nStack trace:\n {3}\n\n Do you want to:\n" +
                                    "(Retry=)Try again.\n(Abort=)Exit the Process.\n Or ignore this site and continue?", WebTitle, WebUrl,
                                    Ex.Message, Ex.StackTrace), "Error writing file", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
                                    if (Result == System.Windows.Forms.DialogResult.Retry)
                                        Retry = true;
                                    else if (Result == System.Windows.Forms.DialogResult.Abort)
                                    {
                                        MessageBox.Show("Process has been aborted by user!");
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
                tabMain.SelectedIndex = 2;
            }
            //Update the list view
            foreach (object user in spuManagerObj.Users.Keys)
            {
                listBoxUsersList.Items.Add(user);
            }
            //Update the unique users count
            labelUsersCount.Text = string.Format("( {0} )", listBoxUsersList.Items.Count);
            #endregion

            #region Save users to a CSV file

            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    spuManagerObj.WriteUserDataToCSVFile(saveFileDialogMain.FileName, EntryForSiteCollections, EntryForSubSites);
                }
            }
            catch (Exception Ex)
            {

                MessageBox.Show(string.Format("Error writing the users list to the disk.\nError details: {0}\nStack trace: {1}",
                    Ex.Message, Ex.StackTrace), "Error writing file", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            #endregion

            MessageBox.Show("Users report has beeen created successfully", "Users Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        private void treeViewSites_AfterCheck(object sender, TreeViewEventArgs e)
        {
            if (UpdatingNode) return;
            UpdatingNode = true;
            TreeNode node = e.Node;

            //if Application node
            if (IsFarm(node))
            {
                //select children
                foreach (TreeNode App in node.Nodes)
                {
                    foreach (TreeNode item in App.Nodes)
                    {
                        if (item.Tag is SPObject)
                        {
                            item.Checked = !item.Checked;
                            if(item.Checked)
                                SelectedSiteCount++;
                            else
                                SelectedSiteCount--;
                        }
                    }
                }

            }
            //if Application node
            if (IsApplication(node))
            {
                //select children
                foreach (TreeNode item in node.Nodes)
                {
                    if (item.Tag is SPObject)
                    {
                        item.Checked = !item.Checked;
                        if (item.Checked)
                            SelectedSiteCount++;
                        else
                            SelectedSiteCount--;
                    }
                }

            }
            //if Application node
            if (IsSiteCollection(node))
            {
                if (node.Checked)
                    SelectedSiteCount++;
                else
                    SelectedSiteCount--;
            }

            if (node.Parent != null)
                node.Parent.Checked = true;

            UpdateSiteCount();
            UpdatingNode = false;
        }
        public void UpdateSiteCount(TreeView SitesTree)
        {
            bool SiteSelected = false;
            foreach (TreeNode App in SitesTree.Nodes)
            {
                SiteSelected = false;
                foreach (TreeNode siteurl in App.Nodes)
                {
                    SiteCount++;
                    if (siteurl.Checked)
                    {
                        SelectedSiteCount++;
                        SiteSelected = true;
                    }
                }
                UpdatingNode = true;
                if (SiteSelected)
                    App.Checked = true;
                else
                    App.Checked = false;
                UpdatingNode = false;
            }
            labelSelectedSites.Text = string.Format("( {0} \\ {1} )", SelectedSiteCount, SiteCount);
            GUIcontroler();
        }
        public bool IsFarm(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag is SPObject)
                return GetSPObjectType(Node.Tag as SPObject) == SPType.Farm;
            return false;
        }
        public bool IsApplication(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag is SPObject)
                return GetSPObjectType(Node.Tag as SPObject) == SPType.WebApplication;
            return false;
        }
        public bool IsSiteCollection(TreeNode Node)
        {
            if (Node != null &&
                Node.Tag != null &&
                Node.Tag is SPObject)
                return GetSPObjectType(Node.Tag as SPObject) == SPType.SiteCollection;
            return false;
        }
        public SPType GetSPObjectType(SPObject spObj)
        {
            if (spObj != null)
                return spObj.WSSType;
            return SPType.Undefined;
        }
       
        private void treeViewSites_BeforeCheck(object sender, TreeViewCancelEventArgs e)
        {
            TreeNode node = e.Node;
            if (!(node.Tag is SPObject)) e.Cancel = true;
        }
        private void buttonSaveSites_Click(object sender, EventArgs e)
        {
            DataTable SiteData = null;
            try
            {
                //SiteData = GetSitesDataWithStorageInfo();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error creating a site collection report.\nError details: {0}\nStack trace: {1}",
                   Ex.Message, Ex.StackTrace), "Error getting the site collections info", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                    MessageBox.Show("Site collection data with their admin has been written successfully to the selected file.",
                                    "Export user to CSV file", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {

                MessageBox.Show(string.Format("Error writing the site collection data to the disk.\nError details: {0}\nStack trace: {1}",
                    Ex.Message, Ex.StackTrace), "Error writing file", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private DataTable GetSitesDataWithStorageInfo(int IncreaseStorage,bool AutoIncreaseStorageQuota)
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("No farm is loaded. Please load the farm SharePoint applications first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("URL");
            Results.Columns.Add("Site Quota (MB)");
            Results.Columns.Add("Site Size (MB)");
            Results.Columns.Add("Quota Limit Increase Value (MB)");
            int I = 1;
            
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                bool SitesQuotaUpdated = false;
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, AutoIncreaseStorageQuota,IncreaseStorage);
                    SitesQuotaUpdated = true;
                }
                foreach (TreeNode siteNode in App.Nodes)
                {
                    if (!siteNode.Checked)
                        continue;
                    bool ApproachedLimit = GetSPObjectProperty(siteNode, "C: Quota Approached Limit") == "True";
                    DataRow newAdminEntry = Results.NewRow();
                    newAdminEntry["I"] = I++;
                    newAdminEntry["Url"] = siteNode.Text;
                    newAdminEntry["Site Quota (MB)"] = GetSPObjectProperty(siteNode, "C: Quota(MB)");
                    newAdminEntry["Site Size (MB)"] = GetSPObjectProperty(siteNode, "C: Storage(MB)");
                    if (ApproachedLimit)
                        newAdminEntry["Quota Limit Increase Value (MB)"] = IncreaseStorage;
                    else
                        newAdminEntry["Quota Limit Increase Value (MB)"] = 0;
                   
                    //Update site quota
                    if (AutoIncreaseStorageQuota &&
                        IncreaseStorage > 0 &&
                        !SitesQuotaUpdated &&
                        ApproachedLimit)
                    {
                        using (SPSite site = new SPSite(siteNode.Text))
                        {
                            while (true)
                            {
                                try
                                {
                                    SPUmanager.UpdateSiteQuota(site, IncreaseStorage);
                                    break;
                                }
                                catch (Exception Ex)
                                {
                                    DialogResult Result = MessageBox.Show(string.Format("Unable to increase the site quota for the site collection {0}.\n\n Error Details:\n{1}", site.Url, Ex.Message),
                                        "Increase site collection quota", MessageBoxButtons.AbortRetryIgnore, MessageBoxIcon.Error);
                                    if (Result == System.Windows.Forms.DialogResult.Abort)
                                    {
                                        throw;
                                    }
                                    else if (Result == System.Windows.Forms.DialogResult.Ignore)
                                    {
                                        newAdminEntry["Quota Limit Increase Value (MB)"] = "0 - Failed to increase quota";
                                        break;
                                    }

                                }
                            }
                        }
                    }
                    //Add entry to the table
                    Results.Rows.Add(newAdminEntry);
                }
            }

            
            return Results;
        }
        private DataTable GetSiteAdministratorsData()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the applications in the farm first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("URL");
            Results.Columns.Add("Admin Name");
            Results.Columns.Add("Admin NTID");
            Results.Columns.Add("Admin Email");
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App,false,0);
                }
                foreach (TreeNode siteurl in App.Nodes)
                {
                    if (!siteurl.Checked)
                        continue;
                    if (siteurl.Nodes.ContainsKey("Admins"))
                    {
                        foreach (TreeNode admin in siteurl.Nodes["Admins"].Nodes)
                        {
                            DataRow newAdminEntry = Results.NewRow();
                            newAdminEntry["I"] = I++;
                            newAdminEntry["Url"] = siteurl.Text;
                            //Get the admin properties
                            newAdminEntry["Admin Name"] = GetSPObjectProperty(admin, "Name");
                            newAdminEntry["Admin NTID"] = GetSPObjectProperty(admin, "LoginName");
                            newAdminEntry["Admin Email"] = GetSPObjectProperty(admin, "Email");
                            //Add entry to the table
                            Results.Rows.Add(newAdminEntry);

                        }
                    }
                }
            }
            return Results;
        }
        private DataTable GenerateLastModifiedDateReport()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the applications in the farm first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("Url");
            Results.Columns.Add("Last Content Modified Date");
            Results.Columns.Add("Last Security Modified Date");
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, false, 0);
                }
                foreach (TreeNode SiteNode in App.Nodes)
                {
                    if (!SiteNode.Checked)
                        continue;

                    DataRow newAdminEntry = Results.NewRow();
                    newAdminEntry["I"] = I++;
                    newAdminEntry["Url"] = SiteNode.Text;
                    newAdminEntry["Last Content Modified Date"] = GetSPObjectProperty(SiteNode, "LastContentModifiedDate");
                    newAdminEntry["Last Security Modified Date"] = GetSPObjectProperty(SiteNode, "LastSecurityModifiedDate");
                    //Add entry to the table
                    Results.Rows.Add(newAdminEntry);
                }
            }
            return Results;
        }
        private DataTable GenerateLastAccessedDateReport()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the applications in the farm first.");
            DataTable Results = new DataTable("Site Collections");
            Results.Columns.Add("I");
            Results.Columns.Add("Url");
            Results.Columns.Add("Last Accessed Date");
            Results.Columns.Add("Enough Auditing Enabled");
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, false, 0);
                }
                foreach (TreeNode SiteNode in App.Nodes)
                {
                    if (!SiteNode.Checked)
                        continue;
                    string SiteCollectionUrl = SiteNode.Text;
                    using (SPSite site = new SPSite(SiteCollectionUrl))
                    {
                        DataRow newAuditEntry = Results.NewRow();
                        newAuditEntry["I"] = I++;
                        newAuditEntry["Url"] = SiteCollectionUrl;
                        try
                        {
                            //Check if auditing is set to capture enough information
                            if (EnoughAuditingIsEnabled(site))
                            {
                                newAuditEntry["Enough Auditing Enabled"] = "True";
                                DateTime? LastAccessedDate = GetLastDateSiteWasAccessed(site);
                                if (LastAccessedDate != null)
                                {
                                    newAuditEntry["Last Accessed Date"] = LastAccessedDate;
                                }
                            }
                            else
                            {
                                newAuditEntry["Last Accessed Date"] = "";
                                newAuditEntry["Enough Auditing Enabled"] = "False";
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            newAuditEntry["Last Accessed Date"] = "Access Denied";
                            newAuditEntry["Enough Auditing Enabled"] = "Access Denied";
                        }
                        catch (Exception Ex)
                        {
                            newAuditEntry["Last Accessed Date"] = "Error - " + Ex.Message;
                            newAuditEntry["Enough Auditing Enabled"] = "Error - " + Ex.Message;
                        }
                        //Add entry to the table
                        Results.Rows.Add(newAuditEntry);
                    }
                    
                }
            }
            return Results;
        }
        private void treeViewSites_AfterSelect(object sender, TreeViewEventArgs e)
        {
            lsvLists.Items.Clear();
            if (e.Node.Tag == null) return;
            if (e.Node.Tag.GetType() == typeof(SPObject))
            {
                SPObject NodeData = e.Node.Tag as SPObject;
                if (NodeData.WSSType == SPType.Undefined && e.Node.Text == "Audit")
                {
                    dgvItems.DataSource = NodeData.Data;
                    tabMain.TabPages[1].Text = "Audit Log";
                    tabMain.SelectedIndex = 1;
                }
                else
                {

                    //Load properties page
                    SPObject SelectedSPObj = (SPObject)e.Node.Tag;
                    LoadPropertiesPage(SelectedSPObj);
                }
            }
            
        }

        private void LoadPropertiesPage(SPObject SelectedSPObj)
        {
            //Load properties page

            foreach (var ValuePair in SelectedSPObj.Properties)
            {
                lsvLists.Items.Add(ValuePair.Key).SubItems.Add(ValuePair.Value);
            }
            lsvLists.Sorting = SortOrder.Ascending;
            lsvLists.Sort();
            tabMain.SelectedIndex = 0;
        }

        private void toolStripButtonConnectToSharePoint_Click(object sender, EventArgs e)
        {
            try
            {
                LoadFarmAndAppsOnly();
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error connection to SharePoint.\nError details: {0}\nStack trace: {1}",
                  Ex.Message, Ex.StackTrace), "Connecting to local farm ...", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void treeViewSites_DoubleClick(object sender, EventArgs e)
        {
            if (treeViewSites.SelectedNode == null) return;

            TreeNode SelectedNode = treeViewSites.SelectedNode;

            if (SelectedNode.Tag != null && 
                SelectedNode.Tag.GetType() == typeof(SPObject))
            {
                SPObject NodeData = SelectedNode.Tag as SPObject;
                if (NodeData.Loaded) return;
                if (NodeData.WSSType == SPType.WebApplication)
                {
                    SPWebService CurrentFarm = SPWebService.ContentService;

                    SPWebApplication CurrentWebApp = CurrentFarm.WebApplications[SelectedNode.Text];
                   
                    //Create Content dbs collection
                    TreeNode ContentDBsCollectionNode = CreateContentDbsCollection(SelectedNode, CurrentWebApp.ContentDatabases.Count);
                    //Load Content DBs
                    LoadContentDb(CurrentWebApp, ContentDBsCollectionNode);

                    //Set the web application as loaded
                    NodeData.Loaded = true;
                }
                else if (NodeData.WSSType == SPType.Undefined && SelectedNode.Text.StartsWith("Audit"))
                {
                    bool AccessDeniedBefore = SelectedNode.Text.Contains("Access Denied");
                    //Load audit data if not loaded
                    if (NodeData.Data != null && NodeData.Data.Columns.Count > 0)
                    {
                        dgvItems.DataSource = NodeData.Data;
                        tabMain.TabPages[1].Text = "Audit Log";
                        tabMain.SelectedIndex = 1;
                    }
                    else
                    {
                        try
                        {
                            using (SPSite site = new SPSite(new Guid(NodeData.ID)))
                            {
                                DataTable AuditLog = GetAuditLog(site);
                                NodeData.Data = AuditLog;
                                dgvItems.DataSource = AuditLog;
                                tabMain.TabPages[1].Text = "Audit Log";
                                tabMain.SelectedIndex = 1;
                                //Remove access denied label if any
                                SelectedNode.Text = "Audit";
                                NodeData.Loaded = true;
                            }
                        }
                        catch (UnauthorizedAccessException)
                        {
                            if (AccessDeniedBefore)
                            {
                                MessageBox.Show("Access denied. Make sure you have site administrator rights to be able to view the audit log.",
                                                "Load Audit Log", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }
                            else
                                SelectedNode.Text += " (Access Denied)";
                        }
                        catch (Exception Ex)
                        {
                            MessageBox.Show("Unable to load audit data." + Ex.Message);
                        }
                    }

                }
                SelectedNode.Expand();
            }
        }
        private SPUser GetUserbyID(int ID,SPSite site)
        {
            if(ID < 0)
                return null;
            SPUser user = null;
            try
            {
                user = site.RootWeb.SiteUsers[ID];
            }
            catch
            { }
            return user;
        }
        private bool EnoughAuditingIsEnabled(SPSite site)
        {
            return ((site.Audit.AuditFlags & SPAuditMaskType.View) == SPAuditMaskType.View);
        }
        private DateTime? GetLastDateSiteWasAccessed(SPSite site)
        {
            //Prepare audit query object for the site collection
            SPAuditQuery AuditQuery = new SPAuditQuery(site);

            //Restrict query only to view events
            AuditQuery.AddEventRestriction(SPAuditEventType.View);

            //Get all view events for the site collection
            SPAuditEntryCollection AuditLog = site.Audit.GetEntries(AuditQuery);

            //Sort view events descending and return the last view date
            List<DateTime> ViewLogsSorted = (from SPAuditEntry AE in AuditLog
                          orderby AE.Occurred descending
                          select AE.Occurred).ToList();
            if (ViewLogsSorted != null && ViewLogsSorted.Count > 0)
                return ViewLogsSorted[0];
            return null;
        }
        private DataTable GetAuditLog(SPSite site)
        {
            //Cache fetched users in this collection
            Dictionary<int, string> Users = new Dictionary<int, string>();

            //Add system accounts
            Users.Add(1073741823, "System Account;System Account");
            Users.Add(9, "System Account;System Account"); //TODO: Confirm that 9 is the system account

            //Prepare the table to populate with audit data
            DataTable Audit = new DataTable();
            Audit.Columns.Add("Document Location");
            Audit.Columns.Add("Event Type");
            Audit.Columns.Add("Event Data");
            Audit.Columns.Add("Event Name");
            Audit.Columns.Add("Event Source");
            Audit.Columns.Add("Item Id");
            Audit.Columns.Add("Item Type");
            Audit.Columns.Add("Location Type");
            Audit.Columns.Add("Occurred",typeof(DateTime));
            Audit.Columns.Add("Site Id");
            Audit.Columns.Add("Source Name");
            Audit.Columns.Add("User Id",typeof(int));
            Audit.Columns.Add("User NTID");
            Audit.Columns.Add("User Name");
            Audit.Columns.Add("Machine IP");
            Audit.Columns.Add("Machine Name");
            SPAuditEntryCollection AuditLog = site.Audit.GetEntries();
            //Sort view events descending and return the last view date
            var AuditLogsSorted = from SPAuditEntry AE in AuditLog
                                             orderby AE.Occurred descending
                                             select AE;
            int PreviousUserID = -1;
            string PreviousUserLogin = "";
            string PreviousUserName = "";

            foreach (var audit in AuditLogsSorted)
            {
                
                DataRow DR = Audit.NewRow();
                DR["Document Location"] = audit.DocLocation;
                DR["Event Type"] = audit.Event;
                DR["Event Data"] = audit.EventData;
                DR["Event Name"] = audit.EventName;
                DR["Event Source"] = audit.EventSource;
                DR["Item Id"] = audit.ItemId;
                DR["Item Type"] = audit.ItemType;
                DR["Location Type"] = audit.LocationType;
                DR["Machine IP"] = audit.MachineIP;
                DR["Machine Name"] = audit.MachineName;
                DR["Occurred"] = audit.Occurred;
                DR["Site Id"] = audit.SiteId;
                DR["Source Name"] = audit.SourceName;
                int UserID = audit.UserId;
                DR["User Id"] = UserID;
                //Get user info from quick cache
                if (UserID == PreviousUserID)
                {
                    DR["User NTID"] = PreviousUserLogin;
                    DR["User Name"] = PreviousUserName;
                }//Get from the regular cache
                else if (Users.ContainsKey(UserID))
                {
                    string[] UserInfo = Users[UserID].Split(';');
                    PreviousUserID = UserID;
                    DR["User NTID"] = PreviousUserLogin = UserInfo[0];
                    DR["User Name"] = PreviousUserName = UserInfo[1];
                }
                else //Not found in cache
                {
                    //Get user from site
                    SPUser user = GetUserbyID(UserID, site);
                    if (user != null)
                    {
                        //store in cache
                        Users.Add(UserID, user.LoginName + ";" + user.Name);
                        PreviousUserID = UserID;
                        DR["User NTID"] = PreviousUserLogin = user.LoginName;
                        DR["User Name"] = PreviousUserName = user.Name;
                    }
                    else
                    {
                        //Store empty user in cache to avoid trying to fetch it again from site
                        Users.Add(UserID," ; ");
                    }
                }
                Audit.Rows.Add(DR);
            }
            return Audit;
        }
        private void LoadAppNodeSiteCollections(string ApplicationID, TreeNode AppNode,bool AutoIncreaseStorageQuota, int QuotaIncrease)
        {
            SPWebService CurrentFarm = SPWebService.ContentService;
            if (CurrentFarm == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;
            SPWebApplication WebApp = CurrentFarm.WebApplications[new Guid(ApplicationID)];
            LoadSiteCollections(WebApp, AppNode, AutoIncreaseStorageQuota, QuotaIncrease);
            UpdatingNode = false;
        }
        private void LoadFarmFeatures(SPFarm FarmObj, TreeNode FarmNode)
        {
            //Find\Create the root features node
            SPWebService CurrentFarm = SPWebService.ContentService;
            TreeNode FeaturesNode = FarmNode.Nodes["Features"];
            if (FeaturesNode == null)
            {
                FeaturesNode = new TreeNode("Features");
                FeaturesNode.ImageIndex = 45;
                FeaturesNode.Tag = SPdalHelper.PopulateCollection(SPType.Feature, CurrentFarm.Farm.FeatureDefinitions.Count,true,false);
            }
            FarmNode.Nodes.Add(FeaturesNode);
            bool FeatureActivated = false;
            UpdatingNode = true;
            TreeNode FeatureNode = null;
            //Get farm features
            
            foreach (SPFeatureDefinition feature in CurrentFarm.Farm.FeatureDefinitions)
            {
                FeatureActivated = false;

                FeatureNode = new TreeNode(feature.DisplayName);
                FeatureNode.Checked = false;
                SPObject Feature = SPdalHelper.PopulateFeature(feature,false);
                //Check if the feature is activated
                if (feature.Scope == SPFeatureScope.Farm)
                {
                    SPFeatureQueryResultCollection Results = CurrentFarm.QueryFeatures(feature.Id);
                    if (Results.Count() > 0) FeatureActivated = true;
                }
                Feature.Properties.Add("C: Active", FeatureActivated.ToString());
                FeatureNode.Tag = Feature;
                FeatureNode.ImageIndex = 45;
                FeaturesNode.Nodes.Add(FeatureNode);

            }

        }
        private void LoadFeatures(object SPObject, TreeNode RootNode, SPFeatureScope Scope)
        {
            
            
            UpdatingNode = true;
            TreeNode FeatureNode = null;
            SPFeatureCollection FeaturesCollection = null;
            //Get features
            switch (Scope)
            {
                case SPFeatureScope.Site:
                    SPSite site = SPObject as SPSite;
                    FeaturesCollection = site.Features;
                    break;
                case SPFeatureScope.Web:
                    SPWeb web = SPObject as SPWeb;
                    FeaturesCollection = web.Features;
                    break;
                case SPFeatureScope.WebApplication:
                    SPWebApplication WebApp = SPObject as SPWebApplication;
                    FeaturesCollection = WebApp.Features;
                    break;
                default:
                    break;
            }
            //Find\Create the root features node
            TreeNode FeaturesNode = RootNode.Nodes["Features"];
            if (FeaturesNode == null)
            {
                FeaturesNode = new TreeNode("Features");
                FeaturesNode.ImageIndex = 45;
                FeaturesNode.Tag = SPdalHelper.PopulateCollection(SPType.Feature, FeaturesCollection.Count,true,false);
            }
            RootNode.Nodes.Add(FeaturesNode);
            foreach (SPFeature feature in FeaturesCollection)
            {
                FeatureNode = new TreeNode(feature.Definition.DisplayName);
                FeatureNode.Checked = false;
                SPObject Feature = SPdalHelper.PopulateFeature(feature,false);
                FeatureNode.Tag = Feature;
                FeatureNode.ImageIndex = 45;
                FeaturesNode.Nodes.Add(FeatureNode);
            }

        }

        private TreeNode CreateSiteCollectionCollectionNode(TreeNode ContentDbNode, int Count)
        {
            TreeNode SiteCollectionCollectionNode = new TreeNode("Site Collections");
            SiteCollectionCollectionNode.Checked = false;
            SiteCollectionCollectionNode.ImageIndex = 21;
            SiteCollectionCollectionNode.Tag = SPdalHelper.PopulateCollection(SPType.SiteCollection, Count, true,false);
            ContentDbNode.Nodes.Add(SiteCollectionCollectionNode);
            return SiteCollectionCollectionNode;
        }
        private void LoadSiteCollections()
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The local farm is not loaded yet. Please load the farm SharePoint applications first.");
            SPWebService CurrentFarm = SPWebService.ContentService;
            SPFarm FarmObj = SPFarm.Local;

            if (CurrentFarm == null || FarmObj == null)
                throw new NullReferenceException(string.Format("Unable to connect to SharePoint", MessageBoxButtons.OK, MessageBoxIcon.Error));
            UpdatingNode = true;

            foreach (TreeNode AppNode in treeViewSites.Nodes[0].Nodes)
            {
                //Skip unchecked nodes
                if (!AppNode.Checked)
                    continue;
                LoadSiteCollections(CurrentFarm.WebApplications[AppNode.Text], AppNode, false, 0);
            }
            UpdatingNode = false;
            UpdateSiteCount();
        }
        private void LoadSiteCollections(SPWebApplication WebApp,TreeNode ContentDbNode, bool AutoIncreaseStorageQuota,int QuotaIncreaseValue)
        {
            UpdatingNode = true;
            TreeNode SiteNode = null;
            TreeNode SiteCollectionCollectionNode = CreateSiteCollectionCollectionNode(ContentDbNode, WebApp.Sites.Count);
            foreach (SPSite sc in WebApp.Sites)
            {
                SiteCount++;
                string Error = "";
                bool QuotaClose = false;
                try
                {
                    //Test the site access
                    DateTime LastModified = sc.RootWeb.LastItemModifiedDate;
                    SiteNode = new TreeNode(sc.Url);
                    SiteNode.Checked = true;
                    //Site Collections
                    SiteNode.ImageIndex = 21;

                    //Add Site collection Admins
                    if (sc.RootWeb.SiteAdministrators.Count > 0)
                    {
                        TreeNode Admins = SiteNode.Nodes.Add("Admins");
                        //Admins icon
                        Admins.ImageIndex = 40;
                        Admins.Name = "Admins";
                        int Increase = 0;
                        if (sc.Quota.StorageMaximumLevel > 0 &&
                            sc.Usage.Storage >= sc.Quota.StorageWarningLevel)
                        {
                            if(AutoIncreaseStorageQuota)
                                Increase = QuotaIncreaseValue;

                            QuotaClose = true;
                        }
                        long Quota = sc.Quota.StorageMaximumLevel / Convert.ToInt64(1024 * 1024);
                        long Storage = sc.Usage.Storage / Convert.ToInt64(1024 * 1024);
                        //Update site collection storage info
                        SPObject SiteCollection = SPdalHelper.PopulateSiteCollection(sc,false);
                        SiteCollection.Properties.Add("C: Quota(MB)", Quota.ToString());
                        SiteCollection.Properties.Add("C: Storage(MB)", Storage.ToString());
                        SiteCollection.Properties.Add("C: Increase(MB)", Increase.ToString());
                        SiteCollection.Properties.Add("C: Quota Approached Limit", QuotaClose?"True":"False");
                        SiteNode.Tag = SiteCollection;
                        SiteNode.Name = SiteCollection.Properties[Reporter.GetIdentifierPropertyName(SiteCollection.WSSType)];
                        foreach (SPUser admin in sc.RootWeb.SiteAdministrators)
                        {
                            TreeNode tempadmin = Admins.Nodes.Add(admin.Name + " (" + admin.LoginName + ")");
                            //User Icon
                            tempadmin.ImageIndex = 37;
                            tempadmin.Tag = SPdalHelper.PopulateUser(admin,false);
                        }
                    }
                    //Update Quotas
                    if (AutoIncreaseStorageQuota && QuotaClose)
                    {
                        SPUmanager.UpdateSiteQuota(sc, QuotaIncreaseValue);
                    }


                    //Add audit data
                    TreeNode Audit = SiteNode.Nodes.Add("Audit");
                    //Audit icon
                    Audit.ImageIndex = 43;
                    Audit.Name = "Audit";
                    SPObject AuditObj = new SPObject("Site", sc.ID, SPType.Undefined);
                    AuditObj.Loaded = false;
                    Audit.Tag = AuditObj;

                    //Load site collection features
                    LoadFeatures(sc, SiteNode, SPFeatureScope.Site);

                    SelectedSiteCount++;
                }
                catch (Exception Ex)
                {
                    Error = " [Error]:" + Ex.Message;
                    SiteNode = new TreeNode(sc.Url + Error);
                    SiteNode.Checked = false;
                    SiteNode.Tag = false;
                    SiteNode.ImageIndex = 41;
                }
                SiteCollectionCollectionNode.Nodes.Add(SiteNode);
                sc.Dispose();
            }
            UpdatingNode = false;
            UpdateSiteCount();
        }

        private void loadAppsOnlyToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                try
                {
                    SiteCount = 0;
                    SelectedSiteCount = 0;
                    LoadFarmAndAppsOnly();
                    tabMain.SelectedIndex = 0;
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error connection to SharePoint.\nError details: {0}\nStack trace: {1}",
                      Ex.Message, Ex.StackTrace), "Connecting to local farm ...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void loadFarmToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                try
                {
                    LoadFarm();
                    tabMain.SelectedIndex = 0;
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error connection to SharePoint.\nError details: {0}\nStack trace: {1}",
                      Ex.Message, Ex.StackTrace), "Connecting to local farm ...", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void usersToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Create report info object
            SPReport ReportData = new SPReport();
            ReportData.Name = "SharePoint Users Report";
            ReportData.Settings.Add("Add a record for each site collection", true);
            ReportData.Settings.Add("Add a record for each sub site", true);


            //Create a new report form
            try
            {
                ReportMain ReportForm = new ReportMain();
                ReportForm.ReportData = ReportData;
                if (ReportForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    bool EntryForSiteCollection = ReportForm.ReportData.Settings["Add a record for each site collection"];
                    bool EntryForEachSubSite = ReportForm.ReportData.Settings["Add a record for each sub site"];
                    GenerateUserReport(EntryForSiteCollection, EntryForEachSubSite);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error creating users report. Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            "Generate User Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
        }

        private void siteAdministratorsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                //Create a new report form
                try
                {
                    if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        using (new HourGlass())
                        {
                            DataTable SiteData = null;
                            SiteData = GetSiteAdministratorsData();
                            SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                        }
                        MessageBox.Show("Site collection data with their admin has been written successfully to the selected file.",
                                        "Generate Site Administrators Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error creating site administrators report. Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                                "Generate Site Administrators Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void quotaStorageToolStripMenuItem_Click(object sender, EventArgs e)
        {

            //Create report info object
            string StorageIncreaseBoolSettingStr = "Increase site collection quotas which reached the storage warning limit with the value below:";
            SPReport ReportData = new SPReport();
            ReportData.Name = "SharePoint Site Storage Report";
            ReportData.Settings.Add(StorageIncreaseBoolSettingStr, false);
            ReportData.Properties.Add("IncreaseValue", new ReportProperty(true, "1", "Increase value by (GB)"));
            ReportData.DisplayUpdateWarning = true;
            ReportData.UpdateWarning = "This report might increase the site storage quotas for the selected site collections depending on the settings you have selected.";


            //Create a new report form
            try
            {
                ReportMain ReportForm = new ReportMain();
                ReportForm.ReportData = ReportData;
                if (ReportForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    DataTable SiteData = null;
                    using (new HourGlass())
                    {
                        bool IncreaseStorageAutomaticlly = ReportForm.ReportData.Settings[StorageIncreaseBoolSettingStr];
                        string IncreaseValue = ReportForm.ReportData.Properties["IncreaseValue"].Value;

                        //Convert from GB to MB
                        SiteData = GetSitesDataWithStorageInfo(Convert.ToInt16((decimal.Parse(IncreaseValue) * 1024)), IncreaseStorageAutomaticlly);
                    }
                    if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        using (new HourGlass())
                        {
                            SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                        }
                        MessageBox.Show("Site collection data with storage info repot has been generated successfully",
                                        "Generate Site Collection Storage Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    }

                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating site collection storage report. Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            "Generate Site Collection Storage Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void openAccessToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //Create report info object
            SPReport ReportData = new SPReport();
            ReportData.Name = "Open Access Report";
            ReportData.Settings.Add("Scan SharePoint lists", true);
            ReportData.Settings.Add("Scan list items", false);
            ReportData.Settings.Add("Scan objects with unique permissions only", true);
            ReportData.Settings.Add("Exclude system lists", true);


            //Create a new report form
            try
            {
                ReportMain ReportForm = new ReportMain();
                ReportForm.ReportData = ReportData;
                if (ReportForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    DataTable Permissions = null;
                    using (new HourGlass())
                    {
                        bool ScanLists = ReportForm.ReportData.Settings["Scan SharePoint lists"];
                        bool ScanListItems = ReportForm.ReportData.Settings["Scan list items"];
                        bool IncludeObjWithUniquePermOnly = ReportForm.ReportData.Settings["Scan objects with unique permissions only"];
                        bool ExcludeSystemLists = ReportForm.ReportData.Settings["Exclude system lists"];
                        Permissions = GenerateOpenAccessReport(ScanLists, ScanListItems, IncludeObjWithUniquePermOnly, ExcludeSystemLists);
                    }
                        if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                        {
                            using (new HourGlass())
                            {
                                SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, Permissions);
                            }
                            MessageBox.Show("Open access repot has been generated successfully",
                                            ReportData.Name, MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                    
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error creating open access report report.\n\nError details:\n{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                            ReportData.Name, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private DataTable GenerateOpenAccessReport(bool CheckLists, bool CheckListItems, bool ReportListssWithUniquePermissionsOnly, bool RemoveSystemLists)
        {
            if (treeViewSites.Nodes.Count <= 0)
                throw new Exception("The farm is not loaded yet. Please load the farm SharePoint applications first.");
            DataTable Results = SPUmanager.InitializePermissionsTable();
            int I = 1;
            foreach (TreeNode App in treeViewSites.Nodes[0].Nodes)
            {
                if (!App.Checked)
                    continue;
                //Check if the site collections are loaded or not
                if (App.Nodes.Count <= 0)
                {
                    //load site collections
                    LoadAppNodeSiteCollections(GetSPObjectProperty(App, "Id"), App, false, 0);
                }
                foreach (TreeNode siteurl in App.Nodes)
                {
                    if (!siteurl.Checked)
                        continue;
                    DataTable sitePermissions = GetOpenAccessForSite(siteurl.Text, CheckLists, CheckListItems, ReportListssWithUniquePermissionsOnly, RemoveSystemLists);
                    if(sitePermissions != null)
                        Results.Merge(sitePermissions, true, MissingSchemaAction.Add);
                }
            }
            return Results;
        }
        private DataTable GetOpenAccessForSite(string siteCollectionUrl,bool CheckLists, bool CheckListItems, bool ReportListssWithUniquePermissionsOnly, bool RemoveSystemLists)
        {
            DataTable Permissions = SPUmanager.InitializePermissionsTable();
            //Exclude the User Information List
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite SiteCollection = new SPSite(siteCollectionUrl))
                {
                    foreach (SPWeb web in SiteCollection.AllWebs)
                    {
                        try
                        {
                            DataTable webPermissions = SPUmanager.GetNtAuthenticatedUsersPermission(web, CheckLists, CheckListItems, ReportListssWithUniquePermissionsOnly, RemoveSystemLists);
                            if(webPermissions != null)
                                Permissions.Merge(webPermissions, true, MissingSchemaAction.Add);
                        }
                        finally
                        {
                            if (web != null)
                                web.Dispose();
                        }
                    }
                }
                
            });
            return Permissions;
        }

        private void loadSiteCollectionsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            using (new HourGlass())
            {
                try
                {
                    LoadSiteCollections();
                }
                catch (Exception Ex)
                {
                    MessageBox.Show(string.Format("Error creating open access report report.\n\nError details:\n{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                                "Load site collections", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void lastModifiedDateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (new HourGlass())
                    {
                        DataTable SiteData = null;
                        SiteData = GenerateLastModifiedDateReport();
                        SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                    }
                    MessageBox.Show("Last modified date report has been written successfully to the selected file.",
                                    "Last Modified Date Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating the last modified date report.\n\nError details:\n{0}\n\nCall stack:\n{1}", Ex.Message, Ex.StackTrace),
                                            "Last Modified Date Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void lastAccessedDateToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (new HourGlass())
                    {
                        DataTable SiteData = null;
                        SiteData = GenerateLastAccessedDateReport();
                        SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, SiteData);
                    }
                    MessageBox.Show("Last accessed date report has been written successfully to the selected file.",
                                    "Last Accessed Date Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating the last accessed date report.\n\nError details:\n{0}\n\nCall stack:\n{1}", Ex.Message, Ex.StackTrace),
                                            "Last Accessed Date Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            //Initializing program
            PickingProperties = false;
            
            //Get the version number
            Version CurentVersion = Assembly.GetEntryAssembly().GetName().Version;
            string Version = CurentVersion.Major.ToString() + "." + CurentVersion.Minor;
            this.Text = this.Text + Version;

            //Check if its running with elevated privileges
            Helper.CheckIfRunningAsAnAdmin(this);
        }

        private void sharePointDatabasesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    using (new HourGlass())
                    {
                        DataTable DatabasesData = null;
                        DatabasesData = GetSPDatabases();
                        SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, DatabasesData);
                    }
                    MessageBox.Show("Databases report has been written successfully to the selected file.",
                                    "Databasese Report", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception Ex)
            {
                MessageBox.Show(string.Format("Error generating database report.\n\nError details:\n{0}\n\nCall stack:\n{1}", Ex.Message, Ex.StackTrace),
                                            "Databasese Report", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void designReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            ReportDesigner = new CreateReportWizard();
            ReportDesigner.PointerToSPObjectsTree = treeViewSites;
            ReportDesigner.PointerToMainForm = this;
            ReportDesigner.Show();
        }

        private void PickPropertiestoolStripMenuItem_Click(object sender, EventArgs e)
        {
            TreeNode SelectedNode = treeViewSites.SelectedNode;
            SPType ObjType = ((SPObject)SelectedNode.Tag).WSSType;
            ReportDesigner.SelectedObjType = ObjType;
            List<string> SelectedProperties = new List<string>();
            foreach (ListViewItem item in lsvLists.SelectedItems)
            {
                SelectedProperties.Add(item.SubItems[0].Text);
            }
            ReportDesigner.SelectedProperties = SelectedProperties;
            PickingProperties = false;
            PickPropertiestoolStripMenuItem.Enabled = false;
            ReportDesigner.PropertyDataPending = true;
            ReportDesigner.Activate();
        }

        private void executeReportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Report reportObj = null;
            //Set the filter of the dialog to report designer
            openFileDialogMain.Filter = Helper.REPORT_DESIGN_FILTER;
            if (openFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                reportObj = Reporter.LoadReportObject(openFileDialogMain.FileName);
            }
            if (reportObj != null)
            {
                DataTable Data = Reporter.ExecuteReport(reportObj, treeViewSites);
                if (Data != null)
                {
                    //Set the filter settings to csv
                    saveFileDialogMain.Filter = Helper.CSV_FILTER;
                    if (saveFileDialogMain.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    {
                        try
                        {
                            using (new HourGlass())
                            {
                                SPUmanager.WriteDataTableToFile(saveFileDialogMain.FileName, Data);
                                //Reporter.SaveToExcel(Data, saveFileDialogMain.FileName);
                            }
                            MessageBox.Show("The designed repot has been executed successfully and saved to the selected location",
                                            "Design a custom report - Save As ..", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                        catch (Exception Ex)
                        {
                            MessageBox.Show("Error executing report" + string.Format("Error details:{0}, Call stack: {1}", Ex.Message, Ex.StackTrace),
                                     "Execute report design", MessageBoxButtons.OK, MessageBoxIcon.Error);

                        }
                    }
                }
            }
        }

        private void PickScopestoolStripMenuItem_Click(object sender, EventArgs e)
        {
             //Check if the farm node is loaded or not
            if (treeViewSites.Nodes.Count == 0) return;
            TreeNode SelectedNode = treeViewSites.SelectedNode;
            //SPType ObjType = ((SPObject)SelectedNode.Tag).WSSType;
            //ReportDesigner.SelectedObjType = ObjType;
            SerializableDictionary<SPType, List<string>> SelectedScopes = new SerializableDictionary<SPType, List<string>>();

            AddNodeScope(SelectedScopes, treeViewSites.Nodes[0].Nodes[1]);
            
            ReportDesigner.SelectedScopes = SelectedScopes;
            PickingScopes = false;
            PickPropertiestoolStripMenuItem.Visible = false;
            PickScopestoolStripMenuItem.Visible = false;
            ReportDesigner.ScopeDataPending = true;
            ReportDesigner.Activate();
        }
        private void AddNodeScope(Dictionary<SPType, List<string>> SelectedScopes, TreeNode Node)
        {
            //Add current tree node
            if (Node == null) return;
            if (Node.Checked && Node.Tag != null)
            {
                SPObject NodeObj = Node.Tag as SPObject;
                if (NodeObj != null &&
                    !NodeObj.Collection && (
                    NodeObj.WSSType == SPType.WebApplication ||
                    NodeObj.WSSType == SPType.ContentDatabase ||
                    NodeObj.WSSType == SPType.SiteCollection ||
                    NodeObj.WSSType == SPType.Site ||
                    NodeObj.WSSType == SPType.List))
                {
                    List<string> Scopes = null;
                    if (SelectedScopes.ContainsKey(NodeObj.WSSType))
                        Scopes = SelectedScopes[NodeObj.WSSType];
                    if (Scopes == null)
                    {
                        Scopes = new List<string>();
                        Scopes.Add(Node.Name);
                        SelectedScopes.Add(NodeObj.WSSType, Scopes);
                    }
                    else
                    {
                        Scopes.Add(Node.Name);
                        SelectedScopes[NodeObj.WSSType] = Scopes;
                    }
                }
            }
            
            //Add sub nodes
            foreach (TreeNode SubNode in Node.Nodes)
            {
                AddNodeScope(SelectedScopes, SubNode);
            }
        }

        private void contextMenuStripPropertiesPicking_Opening(object sender, CancelEventArgs e)
        {
            if (PickingProperties && contextMenuStripPropertiesPicking.SourceControl.GetType() == typeof(ListView))
            {
                if (lsvLists.SelectedItems.Count > 0)
                    PickPropertiestoolStripMenuItem.Visible = true;
                PickScopestoolStripMenuItem.Visible = false;
            }
            else if (PickingScopes && contextMenuStripPropertiesPicking.SourceControl.GetType() == typeof(TreeView))
            {
                if (treeViewSites.Nodes.Count > 0)
                    PickScopestoolStripMenuItem.Visible = true;
                PickPropertiestoolStripMenuItem.Visible = false;
            }
            else
            {
                e.Cancel = true;
                PickScopestoolStripMenuItem.Visible = false;
                PickPropertiestoolStripMenuItem.Visible = false;
            }
        }
       

        
    }


}